package org.ma5d.nio.buffer;

import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class BufferDemo2 {

    // static private final int start = 0;
    // static private final int size = 1024;

    // 内存映射文件io
    @Test
    public void testMappedFileIO() throws Exception {
        // 打开文件，并获取通道
        RandomAccessFile raf = new RandomAccessFile("./01.txt", "rw");
        FileChannel fileChannel = raf.getChannel();

        // 映射文件到内存：从文件起始位置映射1024字节到内存中
        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1024);

        // 使用指定字符集进行解码（假设文件是UTF-8编码）
        Charset charset = StandardCharsets.UTF_8;
        CharBuffer charBuffer = charset.decode(mappedByteBuffer);

        // 打印文件中的内容（如果文件是文本）
        System.out.println("文件内容: " + charBuffer.toString());

        // 清除映射的缓冲区，重新设置为写模式
        mappedByteBuffer.clear();

        // 使用 UTF-8 编码将字符写入内存映射文件
        byte[] newText = "Hello, 这是一个测试".getBytes(StandardCharsets.UTF_8);

        // 确保数据大小不会超出映射范围
        if (newText.length <= mappedByteBuffer.capacity()) {
            // 写入数据到内存映射文件
            mappedByteBuffer.put(newText);

            // 手动设置结尾处的两个字节为 'a' 和 'z' (ASCII)
            mappedByteBuffer.put(0, (byte) 97);  // ASCII 字符 'a'
            mappedByteBuffer.put(1023, (byte) 122); // ASCII 字符 'z'
        } else {
            System.out.println("写入的数据过大，无法写入映射的内存区域！");
        }

        // 关闭文件
        raf.close();
    }

    // 直接缓冲区
    @Test
    public void b03() throws Exception {
        String infile = "./01.txt";
        FileInputStream fin = new FileInputStream(infile);
        FileChannel finChannel = fin.getChannel();

        String outfile = "./002.txt";
        FileOutputStream fout = new FileOutputStream(outfile);
        FileChannel foutChannel = fout.getChannel();

        // 创建直接缓冲区
        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

        while (true) {
            buffer.clear();
            int r = finChannel.read(buffer);
            if (r == -1) {
                break;
            }
            buffer.flip();
            foutChannel.write(buffer);
        }
        finChannel.close();
        foutChannel.close();
        fin.close();
        fout.close();
    }

    // 只读缓冲区
    @Test
    public void b02() {
        ByteBuffer buffer = ByteBuffer.allocate(10);

        for (int i = 0; i < buffer.capacity(); i++) {
            buffer.put((byte) i);
        }

        // 创建只读缓冲区
        ByteBuffer readonly = buffer.asReadOnlyBuffer();

        for (int i = 0; i < buffer.capacity(); i++) {
            byte b = buffer.get(i);
            b *= 10;
            buffer.put(i, b);
        }

        readonly.position(0);
        readonly.limit(buffer.capacity());

        while (readonly.remaining() > 0) {
            System.out.println(readonly.get());
        }
    }

    // 缓冲区分片
    @Test
    public void b01() {
        ByteBuffer buffer = ByteBuffer.allocate(10);

        for (int i = 0; i < buffer.capacity(); i++) {
            buffer.put((byte) i);
        }

        // 创建子缓冲区
        buffer.position(3);
        buffer.limit(7);
        ByteBuffer slice = buffer.slice();

        // 改变子缓冲区内容
        for (int i = 0; i < slice.capacity(); i++) {
            byte b = slice.get(i);
            b *= 10;
            slice.put(i, b);
        }

        buffer.position(0);
        buffer.limit(buffer.capacity());

        while (buffer.remaining() > 0) {
            System.out.println(buffer.get());
        }
    }
}
